using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace BookBarter
{
    public partial class TradeLink
    {
        //class variables
        private static List<TradeLink> tradeLinks = new List<TradeLink>();

        private Guid linkid;
        private TradeRoute tradeRoute;
        private BookWant bookWant;
        private BookHave bookHave;
        private bool notified;
        private AcceptedStatus accepted;
        private TradeLink nextTradeLink;

        //class properties
        public Guid ID
        {
            get { return linkid; }
            private set { linkid = value; }
        }
        public BookWant Want
        {
            get
            {
                return bookWant;
            }
            private set
            {
                bookWant = value;
            }
        }
        public BookHave Have
        {
            get
            {
                return bookHave;
            }
            private set
            {
                bookHave = value;
            }
        }
        public TradeRoute Route
        {
            get
            {
                return tradeRoute;
            }
            private set
            {
                tradeRoute = value;
            }
        }
        public bool Notified
        {
            get { return notified; }
            set
            {
                notified = value;
                Save();
            }
        }
        public AcceptedStatus Accepted
        {
            get { return accepted; }
            set
            {
                accepted = value;
                Save();
            }
        }
        public TradeLink NextTradeLink
        {
            get { return nextTradeLink; }
            internal set
            {
                nextTradeLink = value;
            }
        }
              

        //constructor
        private TradeLink(Guid linkid, TradeRoute route, BookHave have, BookWant want, bool notified, AcceptedStatus accepted)
        {
            this.ID = linkid;
            this.Route = route;
            this.Have = have;
            this.Want = want;
            this.Notified = notified;
            this.Accepted = accepted;
        }

        /// <summary>
        /// creates a new TradeLink Object
        /// </summary>
        /// <param name="route">route the link is in</param>
        /// <param name="have">The book being traded</param>
        /// <param name="want">The want the book is satisfying</param>
        /// <returns>Returns the new TradeLink Object</returns>
        internal static TradeLink CreateNewTradeLink(TradeRoute route, BookHave have, BookWant want)
        {
            TradeLink newTL = null;
            SqlConnection cnx = DatabaseConnectionManager.Current.Connection;
            SqlCommand query = new SqlCommand("EXEC add_trade_link @routeid, @haveid, @wantid, @notified, @accepted", cnx);
            query.Parameters.Add("@routeid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@haveid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@wantid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@notified", System.Data.SqlDbType.Bit);
            query.Parameters.Add("@accepted", System.Data.SqlDbType.Bit);
            query.Parameters["@routeid"].SqlValue = route.ID;
            query.Parameters["@haveid"].SqlValue = have.ID;
            query.Parameters["@wantid"].SqlValue = want.ID;
            query.Parameters["@notified"].SqlValue = 0;
            query.Parameters["@accepted"].SqlValue = 0;
            SqlDataReader result = query.ExecuteReader();
            try
            {
                if (result.Read())
                {
                    if (result.IsDBNull(result.GetOrdinal("linkid")))
                    {
                        result.Close();
                        throw new MalformedTradeLinkRecord("Value is NULL where there should be an ID.");
                    }
                    newTL = GetTradeLink(result.GetGuid(result.GetOrdinal("linkid")), route);
                }
                else
                {
                    result.Close();
                    throw new NewTradeLinkException("Failed to create new TradeChainLink");
                }
            }
            finally
            {
                result.Close();
            }
            tradeLinks.Add(newTL);
            return newTL;
        }

        /// <summary>
        /// Gets a TradeLink with a specific guid and from a specific route
        /// </summary>
        /// <param name="linkid">guid of the TradeLink wanted</param>
        /// <param name="route">route the link must be in</param>
        /// <returns>Returns the requested TradeLink</returns>
        internal static TradeLink GetTradeLink(Guid linkid, TradeRoute route)
        {
            foreach (TradeLink tl in tradeLinks)
                if (tl.ID.Equals(linkid))
                    return tl;
            TradeLink newTL = null;
            SqlConnection cnx = DatabaseConnectionManager.Current.Connection;
            SqlCommand query = new SqlCommand("EXEC get_trade_link @linkid", cnx);
            query.Parameters.Add("@linkid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters["@linkid"].SqlValue = linkid;
            SqlDataReader result = query.ExecuteReader();
            try
            {
                if (result.Read())
                {
                    BookHave have = BookHave.GetBookHave(result.GetGuid(result.GetOrdinal("haveid")));
                    BookWant want = BookWant.GetBookWant(result.GetGuid(result.GetOrdinal("wantid")));
                    bool notified = result.GetBoolean(result.GetOrdinal("notified"));
                    AcceptedStatus accepted;
                    if (result.IsDBNull(result.GetOrdinal("accepted")))
                        accepted = AcceptedStatus.Pending;
                    else
                        if (result.GetBoolean(result.GetOrdinal("accepted")))
                            accepted = AcceptedStatus.Accepted;
                        else
                            accepted = AcceptedStatus.Cancelled;
                    newTL = new TradeLink(linkid, route, have, want, notified, accepted);
                }
                else
                {
                    result.Close();
                    throw new NoSuchTradeLink("TradeLink doesn't exist");
                }
            }
            finally
            {
                result.Close();
            }
            tradeLinks.Add(newTL);
            return newTL;
        }

        /// <summary>
        /// Saves the TradeLink to the database
        /// </summary>
        public void Save()
        {
            SqlConnection cnx = DatabaseConnectionManager.Current.Connection;
            SqlCommand query = new SqlCommand("EXEC update_trade_link @linkid, @routeid, " + 
                "@haveid, @wantid, @notified, @accepted", cnx);
            query.Parameters.Add("@linkid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@routeid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@haveid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@wantid", System.Data.SqlDbType.UniqueIdentifier);
            query.Parameters.Add("@notified", System.Data.SqlDbType.Bit);
            query.Parameters.Add("@accepted", System.Data.SqlDbType.Bit);
            query.Parameters["@linkid"].SqlValue = this.ID;
            query.Parameters["@routeid"].SqlValue = this.Route.ID;
            query.Parameters["@haveid"].SqlValue = this.Have.ID;
            query.Parameters["@wantid"].SqlValue = this.Want.ID;
            query.Parameters["@notified"].SqlValue = this.Notified;
            query.Parameters["@accepted"].SqlValue = this.Accepted;
            query.ExecuteNonQuery();
        }
    }
}
